Skip to content

Improve Notification Panel#3913

Merged
evanpelle merged 1 commit into
mainfrom
notifs
May 21, 2026
Merged

Improve Notification Panel#3913
evanpelle merged 1 commit into
mainfrom
notifs

Conversation

@evanpelle
Copy link
Copy Markdown
Collaborator

@evanpelle evanpelle commented May 12, 2026

Resolves #3910

Description:

  • Split the events HUD into two components: a new <actionable-events> that owns alliance prompts (request / renew) and a slimmed-down <events-display> for everything else.
  • Reworked <events-display> into two visual tiers: dim/scrolling tier 2 on top (trade results, unit losses, donations, alliance status), prominent tier 1 anchored at the bottom (inbound nukes, naval invasion, attack requests, alliance broken, conquered player, chat). Tier 2 caps at the 4 newest entries; events expire after 8s.
  • Added a transient +gold pip above the gold pill in <control-panel>, animated with a small fade-in. Fires for trade ships, trains, donations, and conquest. Trade-ship and train arrivals are removed from the events scroll since they're surfaced here instead.
  • New MessageType.NUKE_DETONATED and a server-side emission in NukeExecution.detonate — once an inbound nuke lands or gets intercepted, the inbound warning vanishes and a "detonated" entry takes its place.
  • displayMessage gained optional unitID and focusPlayerID params so events can link to a unit or a player. Unit captures and destructions now navigate to the unit's last tile when clicked; donations navigate to the other player.
  • ActionableEvents card width matches <events-display>; cards persist until the user clicks Accept/Reject/Renew/Ignore or the server-side request timeout expires.
  • Removed the in-events category filter UI and the gold-amount banner — <events-display> is now a lightweight log that hides entirely when empty.
Screenshot 2026-05-21 at 1 42 30 PM Screenshot 2026-05-21 at 1 41 34 PM

Please complete the following:

  • I have added screenshots for all UI updates
  • I process any text displayed to the user through translateText() and I've added it to the en.json file
  • I have added relevant tests to the test directory
  • I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced

Please put your Discord username so you can be contacted if a bug or regression is found:

evan

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 12, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR introduces a new ActionableEvents UI layer for alliance-related notifications, extends the displayMessage API with unit and focus context, refactors EventsDisplay into tiered rendering, animates gold gains in ControlPanel, updates domain code to emit messages with new parameters, and migrates tests.

Changes

ActionableEvents Layer & Message System Expansion

Layer / File(s) Summary
Display message contract expansion
src/core/game/Game.ts, src/core/game/GameImpl.ts, src/core/game/GameUpdates.ts, src/client/Utils.ts
Game interface and implementation now accept optional unitID and focusPlayerID in displayMessage(). MessageType adds NUKE_DETONATED (categorized as Nuke) and the client maps it to failure severity.
ActionableEvents layer introduction
src/client/hud/layers/ActionableEvents.ts
New actionable-events LitElement controller manages priority-sorted, timed actionable prompts for alliance requests, renewals, and breaks; generates per-alliance renewal prompts with throttling; renders event descriptions and actionable buttons that emit navigation/intent events.
ActionableEvents handlers & render
src/client/hud/layers/ActionableEvents.ts
Handlers for alliance request/extension/broken updates, tick activation, expiry pruning, per-alliance throttling, navigation helper, and the render path for actionable prompts.
GameRenderer integration
src/client/hud/GameRenderer.ts
GameRenderer imports and wires the actionable-events element (query, validate, assign eventBus/game/uiState) and adds it to the renderer layers for tick lifecycle.
UI element routing
index.html
Bottom-right HUD events slot now renders <actionable-events> instead of <events-display>, preserving layout classes and pointer-events behavior.
EventsDisplay simplification
src/client/hud/layers/EventsDisplay.ts
Simplifies GameEvent shape (remove buttons/priority/duration/renewal metadata), changes expiry to fixed 80-tick aging with inbound-warning unit-active checks, tightens alliance-reply handling, removes renewal/extension generation, and renders tier1/tier2 tables via renderEventRow.
ControlPanel gold-gain animation
src/client/hud/layers/ControlPanel.ts
Detects gold gains in tick(), stores latest bigint, restarts keyed pulse id, clears after 2s, and renders a keyed +<amount> pop overlay on desktop and mobile; cleans up timeouts in disconnectedCallback().
Domain code message parameter updates
src/core/execution/NukeExecution.ts, src/core/game/UnitImpl.ts, src/core/game/PlayerImpl.ts, src/core/execution/TradeShipExecution.ts
NukeExecution emits MessageType.NUKE_DETONATED with localized detonation keys for Atom/Hydrogen bombs to impacted players. UnitImpl includes unit id in capture/destruction messages. PlayerImpl includes player id in donateGold messages. TradeShipExecution passes tile context when crediting gold.
Test migration and coverage
tests/client/graphics/layers/ActionableEventsAlliance.test.ts, tests/core/executions/NukeExecution.test.ts
ActionableEventsAlliance.test now constructs ActionableEvents. NukeExecution.test adds MessageType import and tests for NUKE_DETONATED emissions for AtomBomb and HydrogenBomb; MIRVWarhead emits none.
Localization additions
resources/lang/en.json
Adds events_display.atom_bomb_detonated and events_display.hydrogen_bomb_detonated localization keys with {name} placeholder.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚀 Events split in two, alliance prompts now shine,

Gold pops with fanfare on every new line,

Nuke blasts announce with their fury on display,

ActionableEvents brings order to the UI ballet! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changeset fully implements the requirements from #3910 by creating ActionableEvents layer for high-value notifications (alliance requests, nuke detonations) while maintaining EventsDisplay for lower-value notifications (trade ship captures), achieving the two-panel separation requested.
Out of Scope Changes check ✅ Passed All changes directly support the notification separation objective: new ActionableEvents component for actionable prompts, NUKE_DETONATED message type and localization, updated displayMessage signatures for unit/focus context, and ControlPanel gold animation enhancement for UI improvements.
Description check ✅ Passed The PR description is well-related to the changeset, detailing the split of event components, visual tier restructuring, gold pip animation, new message type, and parameter additions.
Title check ✅ Passed The title 'Improve Notification Panel' directly reflects the PR's main objective to refactor and improve notification handling by separating high-value and low-value notifications into distinct components (EventsDisplay and ActionableEvents).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/client/graphics/GameRenderer.ts`:
- Around line 133-141: The code currently logs if
document.querySelector("actionable-events") is not an instance of
ActionableEvents but then continues to dereference actionableEvents (setting
actionableEvents.eventBus, .game, .uiState and later inserting layers), causing
a crash if missing; update the guard around actionableEvents in GameRenderer
(the variable actionableEvents and type ActionableEvents) to perform an early
return or throw after the console.error so no property writes or layer insertion
run when actionableEvents is falsy/incorrect, and apply the same guarded pattern
to the other occurrence around lines where layer insertion happens (the second
actionableEvents usage) to ensure eventBus, game and uiState are only assigned
when actionableEvents is a valid ActionableEvents instance.

In `@src/core/execution/TradeShipExecution.ts`:
- Around line 192-193: Add a core simulation unit test that asserts both source
and destination port gold-bonus events are emitted when TradeShipExecution runs:
locate where TradeShipExecution calls srcPort.owner().addGold(gold,
this.srcPort.tile()) and _dstPort.owner().addGold(gold, this._dstPort.tile())
and write a test in the core simulation test suite that (1) sets up a trade
between two ports, (2) spies or subscribes to the core event/bonus emitter for
the source owner and destination owner, (3) executes the TradeShipExecution, and
(4) asserts that each owner received a gold-add event including the correct gold
amount and that the source event includes the tile context (this.srcPort.tile())
while the destination event includes this._dstPort.tile().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 66197d95-9ab2-47fd-a2c2-0c1c0857e646

📥 Commits

Reviewing files that changed from the base of the PR and between 990eba6 and bb0c053.

📒 Files selected for processing (14)
  • index.html
  • src/client/Utils.ts
  • src/client/graphics/GameRenderer.ts
  • src/client/graphics/layers/ActionableEvents.ts
  • src/client/graphics/layers/ControlPanel.ts
  • src/client/graphics/layers/EventsDisplay.ts
  • src/core/execution/NukeExecution.ts
  • src/core/execution/TradeShipExecution.ts
  • src/core/game/Game.ts
  • src/core/game/GameImpl.ts
  • src/core/game/GameUpdates.ts
  • src/core/game/PlayerImpl.ts
  • src/core/game/UnitImpl.ts
  • tests/client/graphics/layers/ActionableEventsAlliance.test.ts

Comment thread src/client/hud/GameRenderer.ts
Comment on lines +192 to 193
this.srcPort.owner().addGold(gold, this.srcPort.tile());
this._dstPort.owner().addGold(gold, this._dstPort.tile());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Add a core test for source-port gold bonus emission.

Line 192 changes core event output (source-side gold now includes a tile context). Please add a core simulation test that verifies bonus/event emission for both source and destination ports.

As per coding guidelines, "All changes to src/core/ must include tests."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/execution/TradeShipExecution.ts` around lines 192 - 193, Add a core
simulation unit test that asserts both source and destination port gold-bonus
events are emitted when TradeShipExecution runs: locate where TradeShipExecution
calls srcPort.owner().addGold(gold, this.srcPort.tile()) and
_dstPort.owner().addGold(gold, this._dstPort.tile()) and write a test in the
core simulation test suite that (1) sets up a trade between two ports, (2) spies
or subscribes to the core event/bonus emitter for the source owner and
destination owner, (3) executes the TradeShipExecution, and (4) asserts that
each owner received a gold-add event including the correct gold amount and that
the source event includes the tile context (this.srcPort.tile()) while the
destination event includes this._dstPort.tile().

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/core/game/UnitImpl.ts (1)

197-232: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add core tests for new unitID message payload fields.

UnitImpl behavior changed in core by adding this.id() to three displayMessage(...) paths, but no matching UnitImpl tests are included here to lock this contract. Please add tests that assert unitID is present for capture (both sender/receiver messages) and destroy notifications.

As per coding guidelines: “src/core/ ... All changes to src/core/ must include tests”.

Also applies to: 326-342

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/game/GameImpl.ts`:
- Around line 936-939: The code computes focusID by calling
this.player(focusPlayerID).smallID() without ensuring the player exists; use the
existing hasPlayer() guard to avoid the player() call when the ID is invalid.
Change the ternary to first check focusPlayerID !== undefined &&
this.hasPlayer(focusPlayerID) and only then call
this.player(focusPlayerID).smallID(); otherwise set focusID to undefined (or
handle per existing semantics), so GameImpl.player() cannot be invoked with a
missing PlayerID.
- Around line 929-930: Tests are missing for the new optional parameters on
GameImpl.displayMessage: add unit tests that call GameImpl.displayMessage (or
helper wrapper used in tests) and assert the produced GameUpdate with type
GameUpdateType.DisplayEvent contains the passed unitID as-is and the
focusPlayerID converted to smallID in the payload's DisplayEvent, and also
assert behavior when each optional parameter is undefined (i.e., absent from the
payload). Target the GameImpl.displayMessage invocation paths updated around
DisplayEvent and verify the update payload fields for unitID and focusPlayerID
(including conversion logic) in positive and undefined cases.

In `@tests/core/executions/NukeExecution.test.ts`:
- Around line 188-200: The test currently constructs a NukeExecution for
UnitType.MIRVWarhead with a null launch ref, so the detonation path isn't
exercised; update the test to create a valid missile silo (or other valid launch
unit) for 'player', obtain its reference (use game.ref(...) or the created
unit's ref) and pass that ref into new NukeExecution(UnitType.MIRVWarhead,
player, game.ref(50, 50), <siloRef>) so the MIRV launch code in NukeExecution is
executed, then run executeTicks(game, 200) and assert that game.displayMessage
was not called with NUKE_DETONATED. Ensure you reference NukeExecution,
UnitType.MIRVWarhead, and game.displayMessage when making these changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 89dee3df-72e9-4227-a64f-8adc37b0882a

📥 Commits

Reviewing files that changed from the base of the PR and between bb0c053 and db6b0cd.

📒 Files selected for processing (16)
  • index.html
  • resources/lang/en.json
  • src/client/Utils.ts
  • src/client/graphics/GameRenderer.ts
  • src/client/graphics/layers/ActionableEvents.ts
  • src/client/graphics/layers/ControlPanel.ts
  • src/client/graphics/layers/EventsDisplay.ts
  • src/core/execution/NukeExecution.ts
  • src/core/execution/TradeShipExecution.ts
  • src/core/game/Game.ts
  • src/core/game/GameImpl.ts
  • src/core/game/GameUpdates.ts
  • src/core/game/PlayerImpl.ts
  • src/core/game/UnitImpl.ts
  • tests/client/graphics/layers/ActionableEventsAlliance.test.ts
  • tests/core/executions/NukeExecution.test.ts
✅ Files skipped from review due to trivial changes (1)
  • resources/lang/en.json
🚧 Files skipped from review as they are similar to previous changes (12)
  • src/core/execution/TradeShipExecution.ts
  • src/core/game/GameUpdates.ts
  • src/client/Utils.ts
  • index.html
  • src/client/graphics/GameRenderer.ts
  • src/core/game/Game.ts
  • tests/client/graphics/layers/ActionableEventsAlliance.test.ts
  • src/core/execution/NukeExecution.ts
  • src/core/game/PlayerImpl.ts
  • src/client/graphics/layers/ControlPanel.ts
  • src/client/graphics/layers/ActionableEvents.ts
  • src/client/graphics/layers/EventsDisplay.ts

Comment thread src/core/game/GameImpl.ts
Comment thread src/core/game/GameImpl.ts
Comment thread tests/core/executions/NukeExecution.test.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/client/hud/layers/ActionableEvents.ts (1)

1-326: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix formatting to unblock CI.

Prettier is failing for this file in the pipeline; please run the formatter before merge.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/hud/layers/ActionableEvents.ts` around lines 1 - 326,
Prettier/formatting errors are causing CI to fail; run the project's formatter
(Prettier) or apply the repo's eslint --fix/format settings to this file so it
matches the project's style. Specifically reformat the ActionableEvents class
and its methods (tick, render, checkForAllianceExpirations,
onAllianceRequestEvent, onAllianceExtensionEvent, onBrokeAllianceEvent,
addEvent/removeEvent) so spacing, indentation and line breaks conform to the
repo Prettier configuration, then re-run the linter/CI to confirm the formatting
issue is resolved.
src/client/hud/layers/EventsDisplay.ts (1)

1-1: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Run Prettier to fix formatting issues.

Pipeline reports code style issues. Run npx prettier --write src/client/hud/layers/EventsDisplay.ts before merge.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/hud/layers/EventsDisplay.ts` at line 1, Formatting in
EventsDisplay.ts is out of sync with project Prettier settings; run the
formatter and commit the result. Run npx prettier --write on the file (or your
repo's configured formatter) and ensure the import line and overall file
containing the EventsDisplay class/component (e.g., the import { html,
LitElement } line and the EventsDisplay class definition) are reformatted, then
stage and commit the updated formatting changes.
🧹 Nitpick comments (2)
src/client/hud/layers/ControlPanel.ts (1)

460-474: 💤 Low value

Inline styles in light DOM are acceptable here.

Since shadow DOM is disabled for Tailwind compatibility, this <style> block lives in the component's template and gets diffed normally by Lit (no duplication). The class name gold-gain-pop is specific enough to avoid conflicts.

One optional improvement: if this animation is reused elsewhere later, consider extracting it to a shared CSS file.
,

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/hud/layers/ControlPanel.ts` around lines 460 - 474, The inline
<style> block defining the gold-gain-pop keyframes and .gold-gain-pop class is
acceptable in ControlPanel.ts, but if you want reuse or avoid duplication
extract the animation to a shared CSS file: create a shared stylesheet (e.g.,
animations.css or shared-animations.ts) containing the `@keyframes` gold-gain-pop
and .gold-gain-pop rule, export or import that stylesheet into ControlPanel.ts
and replace the inline <style> with an import or reference; ensure the selector
name (gold-gain-pop) and keyframe name remain unchanged so existing usage in
ControlPanel (class="gold-gain-pop") continues to work.
src/client/hud/layers/EventsDisplay.ts (1)

208-208: 💤 Low value

Redundant requestUpdate() call on every tick.

Line 205 already triggers a re-render when events change, and _isVisible changes on lines 162/169 do the same. This unconditional call forces a re-render every tick (~10 times/second) even when nothing changed.

♻️ Suggested fix
     if (this.events.length !== remainingEvents.length) {
       this.events = remainingEvents;
       this.requestUpdate();
     }
-
-    this.requestUpdate();
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/hud/layers/EventsDisplay.ts` at line 208, The unconditional
this.requestUpdate() in the EventsDisplay tick handler causes unnecessary
re-renders; remove that call and rely on the existing update paths that already
call requestUpdate() when events change (the events update mechanism) or when
_isVisible is toggled, or guard it so it only calls requestUpdate() when the
events list or _isVisible actually changed. Locate the tick handler inside the
EventsDisplay class (where requestUpdate() is called each tick) and either
delete that call or replace it with a boolean check against the current
events/visibility state (use the _isVisible property and whatever internal
events collection or last-known-events snapshot the class uses) so renders only
happen on real state changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/client/hud/layers/ActionableEvents.ts`:
- Around line 184-188: The loop that cleans stale alliances (iterating
this.alliancesCheckedAt and calling removeAllianceRenewalEvents(allianceId))
doesn't call requestUpdate(), so removed renewal prompts remain visible until
another update; update the cleanup paths (the loop at the top of
ActionableEvents and the similar code around lines 76-84) to call
this.requestUpdate() after deletions (or call requestUpdate() inside
removeAllianceRenewalEvents when it actually mutates this.events) so the
component re-renders immediately when alliance renewal events are removed.

---

Outside diff comments:
In `@src/client/hud/layers/ActionableEvents.ts`:
- Around line 1-326: Prettier/formatting errors are causing CI to fail; run the
project's formatter (Prettier) or apply the repo's eslint --fix/format settings
to this file so it matches the project's style. Specifically reformat the
ActionableEvents class and its methods (tick, render,
checkForAllianceExpirations, onAllianceRequestEvent, onAllianceExtensionEvent,
onBrokeAllianceEvent, addEvent/removeEvent) so spacing, indentation and line
breaks conform to the repo Prettier configuration, then re-run the linter/CI to
confirm the formatting issue is resolved.

In `@src/client/hud/layers/EventsDisplay.ts`:
- Line 1: Formatting in EventsDisplay.ts is out of sync with project Prettier
settings; run the formatter and commit the result. Run npx prettier --write on
the file (or your repo's configured formatter) and ensure the import line and
overall file containing the EventsDisplay class/component (e.g., the import {
html, LitElement } line and the EventsDisplay class definition) are reformatted,
then stage and commit the updated formatting changes.

---

Nitpick comments:
In `@src/client/hud/layers/ControlPanel.ts`:
- Around line 460-474: The inline <style> block defining the gold-gain-pop
keyframes and .gold-gain-pop class is acceptable in ControlPanel.ts, but if you
want reuse or avoid duplication extract the animation to a shared CSS file:
create a shared stylesheet (e.g., animations.css or shared-animations.ts)
containing the `@keyframes` gold-gain-pop and .gold-gain-pop rule, export or
import that stylesheet into ControlPanel.ts and replace the inline <style> with
an import or reference; ensure the selector name (gold-gain-pop) and keyframe
name remain unchanged so existing usage in ControlPanel (class="gold-gain-pop")
continues to work.

In `@src/client/hud/layers/EventsDisplay.ts`:
- Line 208: The unconditional this.requestUpdate() in the EventsDisplay tick
handler causes unnecessary re-renders; remove that call and rely on the existing
update paths that already call requestUpdate() when events change (the events
update mechanism) or when _isVisible is toggled, or guard it so it only calls
requestUpdate() when the events list or _isVisible actually changed. Locate the
tick handler inside the EventsDisplay class (where requestUpdate() is called
each tick) and either delete that call or replace it with a boolean check
against the current events/visibility state (use the _isVisible property and
whatever internal events collection or last-known-events snapshot the class
uses) so renders only happen on real state changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2a3ef376-d805-4a43-86ab-2420b74f9d6d

📥 Commits

Reviewing files that changed from the base of the PR and between db6b0cd and e9d0bcc.

📒 Files selected for processing (7)
  • index.html
  • resources/lang/en.json
  • src/client/Utils.ts
  • src/client/hud/GameRenderer.ts
  • src/client/hud/layers/ActionableEvents.ts
  • src/client/hud/layers/ControlPanel.ts
  • src/client/hud/layers/EventsDisplay.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • resources/lang/en.json
  • index.html

Comment on lines +184 to +188
for (const [allianceId] of this.alliancesCheckedAt) {
if (!currentAllianceIds.has(allianceId)) {
this.removeAllianceRenewalEvents(allianceId);
this.alliancesCheckedAt.delete(allianceId);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Trigger a re-render when stale alliance prompts are removed.

At Line 186, cleanup can remove entries from this.events, but this path does not call requestUpdate(). A removed renewal prompt can stay visible until another unrelated update occurs.

Proposed fix
   for (const [allianceId] of this.alliancesCheckedAt) {
     if (!currentAllianceIds.has(allianceId)) {
+      const before = this.events.length;
       this.removeAllianceRenewalEvents(allianceId);
+      if (this.events.length !== before) {
+        this.requestUpdate();
+      }
       this.alliancesCheckedAt.delete(allianceId);
     }
   }

Also applies to: 76-84

🧰 Tools
🪛 GitHub Actions: 🧪 CI / 🎨 Prettier

[warning] Prettier reported formatting issues in this file.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/hud/layers/ActionableEvents.ts` around lines 184 - 188, The loop
that cleans stale alliances (iterating this.alliancesCheckedAt and calling
removeAllianceRenewalEvents(allianceId)) doesn't call requestUpdate(), so
removed renewal prompts remain visible until another update; update the cleanup
paths (the loop at the top of ActionableEvents and the similar code around lines
76-84) to call this.requestUpdate() after deletions (or call requestUpdate()
inside removeAllianceRenewalEvents when it actually mutates this.events) so the
component re-renders immediately when alliance renewal events are removed.

@sardidefcon
Copy link
Copy Markdown
Contributor

bro evan where are the damn screenshots?! 🤣

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/core/game/UnitImpl.ts (1)

216-231: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add core tests for the new unitID message argument.

Lines 222, 230, and 341 change core message payload shape, but this diff does not include core tests that assert unitID is emitted for capture and destroy flows.

As per coding guidelines, "All changes to src/core/ must include tests."

Also applies to: 335-342

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/game/UnitImpl.ts` around lines 216 - 231, Add core unit tests that
assert the new "unitID" message argument is present for both capture and destroy
flows: simulate the capture flow in UnitImpl and the destroy flow, spy/mock the
mg.displayMessage calls for MessageType.UNIT_CAPTURED_BY_ENEMY and
MessageType.CAPTURED_ENEMY_UNIT (and the destroy-related MessageType used in
UnitImpl), and assert the message payload includes unitID equal to the unit's
id() (and that other payload fields remain unchanged). Use UnitImpl to trigger
the flows, intercept mg.displayMessage, and add assertions that the emitted
payload contains unitID for both the capture and destroy scenarios.
🧹 Nitpick comments (2)
src/client/hud/layers/ActionableEvents.ts (1)

148-150: 💤 Low value

Add a guard before accessing alliance.other.

If alliance.other refers to a player that no longer exists (e.g., conquered), this.game.player() could throw. Consider using playerBySmallID() which returns TerraNullius for invalid IDs, then check .isPlayer().

Proposed defensive check
       this.alliancesCheckedAt.set(alliance.id, this.game.ticks());

-      const other = this.game.player(alliance.other) as PlayerView;
+      const otherResult = this.game.playerBySmallID(alliance.other);
+      if (!otherResult.isPlayer()) continue;
+      const other = otherResult as PlayerView;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/hud/layers/ActionableEvents.ts` around lines 148 - 150, The code
currently calls this.game.player(alliance.other) which may throw if
alliance.other refers to a non-existent player; replace that call with
this.game.playerBySmallID(alliance.other) and guard the result by checking
.isPlayer() (or handling TerraNullius) before using it—update the variable used
(e.g., other) and bail out or skip processing when !other.isPlayer() to avoid
exceptions when the referenced player was conquered or removed.
src/client/hud/layers/ControlPanel.ts (1)

460-474: 💤 Low value

Consider extracting keyframes to a static style or global CSS.

The inline <style> in render() works, but since shadow DOM is disabled, these styles are global anyway. Moving them to static styles or your global CSS file would be slightly cleaner — though not blocking since ControlPanel is a singleton.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/hud/layers/ControlPanel.ts` around lines 460 - 474, Move the
inline <style> block out of ControlPanel.render(): remove the embedded
`@keyframes` gold-gain-pop and .gold-gain-pop rules from the JSX returned by the
render method and instead declare them either in the ControlPanel component's
static styles property or in the global CSS file; update references to the
animation class (gold-gain-pop) to remain unchanged so existing uses still
apply. Locate the ControlPanel class and its render() method to remove the
inline style and add the `@keyframes` gold-gain-pop and .gold-gain-pop rules to
the component's static styles (or global stylesheet) so the animation stays
available without injecting global styles in render().
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/game/PlayerImpl.ts`:
- Around line 855-866: The donation messages currently use the requested
variable `gold` which can over-report the actual transferred amount; update the
two this.mg.displayMessage calls in PlayerImpl (the sender and recipient
messages) to pass `removed` instead of `gold` for the numeric value and to call
renderNumber(removed) for the formatted display; locate the calls to
this.mg.displayMessage around the donation logic (referencing recipient.id(),
this.id(), this.displayName(), renderNumber) and replace the `gold` usages with
`removed`.

---

Outside diff comments:
In `@src/core/game/UnitImpl.ts`:
- Around line 216-231: Add core unit tests that assert the new "unitID" message
argument is present for both capture and destroy flows: simulate the capture
flow in UnitImpl and the destroy flow, spy/mock the mg.displayMessage calls for
MessageType.UNIT_CAPTURED_BY_ENEMY and MessageType.CAPTURED_ENEMY_UNIT (and the
destroy-related MessageType used in UnitImpl), and assert the message payload
includes unitID equal to the unit's id() (and that other payload fields remain
unchanged). Use UnitImpl to trigger the flows, intercept mg.displayMessage, and
add assertions that the emitted payload contains unitID for both the capture and
destroy scenarios.

---

Nitpick comments:
In `@src/client/hud/layers/ActionableEvents.ts`:
- Around line 148-150: The code currently calls this.game.player(alliance.other)
which may throw if alliance.other refers to a non-existent player; replace that
call with this.game.playerBySmallID(alliance.other) and guard the result by
checking .isPlayer() (or handling TerraNullius) before using it—update the
variable used (e.g., other) and bail out or skip processing when
!other.isPlayer() to avoid exceptions when the referenced player was conquered
or removed.

In `@src/client/hud/layers/ControlPanel.ts`:
- Around line 460-474: Move the inline <style> block out of
ControlPanel.render(): remove the embedded `@keyframes` gold-gain-pop and
.gold-gain-pop rules from the JSX returned by the render method and instead
declare them either in the ControlPanel component's static styles property or in
the global CSS file; update references to the animation class (gold-gain-pop) to
remain unchanged so existing uses still apply. Locate the ControlPanel class and
its render() method to remove the inline style and add the `@keyframes`
gold-gain-pop and .gold-gain-pop rules to the component's static styles (or
global stylesheet) so the animation stays available without injecting global
styles in render().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7b2004ce-3c45-4b61-8362-060849d61d91

📥 Commits

Reviewing files that changed from the base of the PR and between e9d0bcc and 219f694.

📒 Files selected for processing (16)
  • index.html
  • resources/lang/en.json
  • src/client/Utils.ts
  • src/client/hud/GameRenderer.ts
  • src/client/hud/layers/ActionableEvents.ts
  • src/client/hud/layers/ControlPanel.ts
  • src/client/hud/layers/EventsDisplay.ts
  • src/core/execution/NukeExecution.ts
  • src/core/execution/TradeShipExecution.ts
  • src/core/game/Game.ts
  • src/core/game/GameImpl.ts
  • src/core/game/GameUpdates.ts
  • src/core/game/PlayerImpl.ts
  • src/core/game/UnitImpl.ts
  • tests/client/graphics/layers/ActionableEventsAlliance.test.ts
  • tests/core/executions/NukeExecution.test.ts
✅ Files skipped from review due to trivial changes (1)
  • resources/lang/en.json

Comment thread src/core/game/PlayerImpl.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/core/game/UnitImpl.ts (2)

216-232: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add tests for unit ownership change messages with unit context.

The displayMessage calls in setOwner now include this.id() as the unitID parameter, but no tests verify this behavior. As per coding guidelines, all changes to src/core/ must include tests.

As per coding guidelines: "All changes to src/core/ must include tests"

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/game/UnitImpl.ts` around lines 216 - 232, Add unit tests that assert
UnitImpl.setOwner triggers mg.displayMessage with the unitID equal to the unit's
id (this.id()). Specifically, create tests that instantiate a UnitImpl,
stub/mock its message gateway (mg) to capture calls, call UnitImpl.setOwner (or
the method containing the shown displayMessage calls), and assert that
mg.displayMessage is invoked for MessageType.UNIT_CAPTURED_BY_ENEMY and
MessageType.CAPTURED_ENEMY_UNIT with the final argument equal to the unit's id;
reference UnitImpl.setOwner, mg.displayMessage,
MessageType.UNIT_CAPTURED_BY_ENEMY, and MessageType.CAPTURED_ENEMY_UNIT when
locating the code under test.

335-342: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add tests for unit destruction messages with unit context.

The displayMessage call in displayMessageOnDeleted now includes this.id() as the unitID parameter, but no tests verify this behavior. As per coding guidelines, all changes to src/core/ must include tests.

As per coding guidelines: "All changes to src/core/ must include tests"

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/game/UnitImpl.ts` around lines 335 - 342, Add a unit test that
asserts UnitImpl.displayMessageOnDeleted invokes MessageGroup.displayMessage
with MessageType.UNIT_DESTROYED and passes the deleted unit's id as the unitID
parameter: create a test that constructs a UnitImpl (or a minimal stub),
spies/mocks its mg (MessageGroup) and owner(), calls displayMessageOnDeleted (or
the code path that triggers the shown this.mg.displayMessage), and verifies the
mock received arguments including the context { unit: this._type } and that the
unitID argument equals the unit's id (this.id()). Use the existing test
harness/mock utilities to target UnitImpl.displayMessageOnDeleted,
MessageGroup.displayMessage, and MessageType.UNIT_DESTROYED.
src/core/game/PlayerImpl.ts (1)

849-867: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add tests for donateGold display message focusPlayerID

donateGold now passes focusPlayerID into displayMessage (so the UI can focus the other player for the “sent” vs “received” gold events), but the existing donation tests only check gold amounts/success and do not assert any DisplayEvent/displayMessage payloads for these gold messages. Add a test that spies on game.displayMessage (or checks GameUpdateType.DisplayEvent) and asserts the last positional arg (focusPlayerID) is recipient.id() for SENT_GOLD_TO_PLAYER and this.id() for RECEIVED_GOLD_FROM_PLAYER.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/game/PlayerImpl.ts` around lines 849 - 867, Add tests for donateGold
to assert the displayMessage focusPlayerID is set correctly: spy on or inspect
game.displayMessage / GameUpdateType.DisplayEvent after calling
PlayerImpl.donateGold and assert the call for MessageType.SENT_GOLD_TO_PLAYER
has its last positional argument equal to recipient.id() and the call for
MessageType.RECEIVED_GOLD_FROM_PLAYER has its last positional argument equal to
donor.id() (use the PlayerImpl instance's id()). Locate usages of donateGold,
displayMessage, and MessageType.SENT_GOLD_TO_PLAYER /
MessageType.RECEIVED_GOLD_FROM_PLAYER in the test suite, invoke donateGold with
a valid amount, capture the display events, and assert the final argument
(focusPlayerID) matches the expected player id for each message type.
♻️ Duplicate comments (3)
src/client/hud/GameRenderer.ts (1)

124-132: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Guard actionableEvents property assignments after error check.

The code checks if actionableEvents is an ActionableEvents instance and logs an error, but then continues to set properties on Line 130-132 regardless. If the element is missing or wrong type, this will crash.

🛡️ Proposed fix
  const actionableEvents = document.querySelector(
    "actionable-events",
  ) as ActionableEvents;
  if (!(actionableEvents instanceof ActionableEvents)) {
    console.error("actionable events not found");
+   throw new Error("actionable-events element is required but not found");
  }
  actionableEvents.eventBus = eventBus;
  actionableEvents.game = game;
  actionableEvents.uiState = uiState;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/hud/GameRenderer.ts` around lines 124 - 132, The code retrieves
actionableEvents and logs an error if it's not an ActionableEvents but then
unconditionally assigns actionableEvents.eventBus, .game, and .uiState; guard
those assignments by only performing them when actionableEvents is an instance
of ActionableEvents (or early-return/throw after the error). Update the block in
GameRenderer.ts around actionableEvents so that after the instanceof check you
either return/exit on error or wrap the three assignments (eventBus, game,
uiState) inside the successful branch that confirms actionableEvents is an
ActionableEvents.
src/core/execution/TradeShipExecution.ts (1)

192-192: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Add core test for source-port gold bonus with tile context.

Line 192 now passes the source port's tile to addGold, changing the event emission signature. As per coding guidelines, all changes to src/core/ must include tests.

As per coding guidelines: "All changes to src/core/ must include tests"

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/execution/TradeShipExecution.ts` at line 192, The change to
TradeShipExecution using this.srcPort.tile() when calling
srcPort.owner().addGold alters the addGold event signature and requires a core
test that verifies the source-port gold bonus emits with the tile context; add a
unit test in the core test suite that constructs the minimal game state (a
srcPort with owner and tile, and a TradeShipExecution invocation or equivalent
helper), triggers the gold-award path (calling TradeShipExecution.execute or the
relevant method), and asserts that addGold was called/emitted with both the
correct gold amount and the source port's tile; reference TradeShipExecution,
srcPort.owner().addGold, and srcPort.tile() when locating where to add the test.
src/client/hud/layers/ActionableEvents.ts (1)

184-189: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add requestUpdate() after removing stale alliance renewal events.

The cleanup loop removes alliance renewal events (Line 186) but doesn't call requestUpdate(), so removed prompts stay visible until another unrelated update triggers a re-render.

🔄 Proposed fix
   for (const [allianceId] of this.alliancesCheckedAt) {
     if (!currentAllianceIds.has(allianceId)) {
+      const before = this.events.length;
       this.removeAllianceRenewalEvents(allianceId);
       this.alliancesCheckedAt.delete(allianceId);
+      if (this.events.length !== before) {
+        this.requestUpdate();
+      }
     }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/hud/layers/ActionableEvents.ts` around lines 184 - 189, The
cleanup loop iterating this.alliancesCheckedAt removes stale alliance renewal
events via removeAllianceRenewalEvents(allianceId) but doesn't trigger a
re-render; after calling removeAllianceRenewalEvents(allianceId) and deleting
from this.alliancesCheckedAt, call requestUpdate() so the UI reflects the
removed prompts. Update the loop in ActionableEvents (the block referencing
this.alliancesCheckedAt and removeAllianceRenewalEvents) to invoke
requestUpdate() once a removal occurs (or once after the loop if multiple
removals) to force an update.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/client/hud/GameRenderer.ts`:
- Line 279: In GameRenderer, ensure the element returned by the querySelector
for "actionableEvents" is validated before being appended to the layers array:
update the guard around the querySelector (the code that locates
actionableEvents) to check for null/undefined and only push actionableEvents
into layers if it is a truthy HTMLElement; if the selector fails, skip adding it
(or log/debug) so layers never contains an invalid entry. Ensure references to
actionableEvents and the layers array are updated accordingly so downstream code
always receives a valid element.

---

Outside diff comments:
In `@src/core/game/PlayerImpl.ts`:
- Around line 849-867: Add tests for donateGold to assert the displayMessage
focusPlayerID is set correctly: spy on or inspect game.displayMessage /
GameUpdateType.DisplayEvent after calling PlayerImpl.donateGold and assert the
call for MessageType.SENT_GOLD_TO_PLAYER has its last positional argument equal
to recipient.id() and the call for MessageType.RECEIVED_GOLD_FROM_PLAYER has its
last positional argument equal to donor.id() (use the PlayerImpl instance's
id()). Locate usages of donateGold, displayMessage, and
MessageType.SENT_GOLD_TO_PLAYER / MessageType.RECEIVED_GOLD_FROM_PLAYER in the
test suite, invoke donateGold with a valid amount, capture the display events,
and assert the final argument (focusPlayerID) matches the expected player id for
each message type.

In `@src/core/game/UnitImpl.ts`:
- Around line 216-232: Add unit tests that assert UnitImpl.setOwner triggers
mg.displayMessage with the unitID equal to the unit's id (this.id()).
Specifically, create tests that instantiate a UnitImpl, stub/mock its message
gateway (mg) to capture calls, call UnitImpl.setOwner (or the method containing
the shown displayMessage calls), and assert that mg.displayMessage is invoked
for MessageType.UNIT_CAPTURED_BY_ENEMY and MessageType.CAPTURED_ENEMY_UNIT with
the final argument equal to the unit's id; reference UnitImpl.setOwner,
mg.displayMessage, MessageType.UNIT_CAPTURED_BY_ENEMY, and
MessageType.CAPTURED_ENEMY_UNIT when locating the code under test.
- Around line 335-342: Add a unit test that asserts
UnitImpl.displayMessageOnDeleted invokes MessageGroup.displayMessage with
MessageType.UNIT_DESTROYED and passes the deleted unit's id as the unitID
parameter: create a test that constructs a UnitImpl (or a minimal stub),
spies/mocks its mg (MessageGroup) and owner(), calls displayMessageOnDeleted (or
the code path that triggers the shown this.mg.displayMessage), and verifies the
mock received arguments including the context { unit: this._type } and that the
unitID argument equals the unit's id (this.id()). Use the existing test
harness/mock utilities to target UnitImpl.displayMessageOnDeleted,
MessageGroup.displayMessage, and MessageType.UNIT_DESTROYED.

---

Duplicate comments:
In `@src/client/hud/GameRenderer.ts`:
- Around line 124-132: The code retrieves actionableEvents and logs an error if
it's not an ActionableEvents but then unconditionally assigns
actionableEvents.eventBus, .game, and .uiState; guard those assignments by only
performing them when actionableEvents is an instance of ActionableEvents (or
early-return/throw after the error). Update the block in GameRenderer.ts around
actionableEvents so that after the instanceof check you either return/exit on
error or wrap the three assignments (eventBus, game, uiState) inside the
successful branch that confirms actionableEvents is an ActionableEvents.

In `@src/client/hud/layers/ActionableEvents.ts`:
- Around line 184-189: The cleanup loop iterating this.alliancesCheckedAt
removes stale alliance renewal events via
removeAllianceRenewalEvents(allianceId) but doesn't trigger a re-render; after
calling removeAllianceRenewalEvents(allianceId) and deleting from
this.alliancesCheckedAt, call requestUpdate() so the UI reflects the removed
prompts. Update the loop in ActionableEvents (the block referencing
this.alliancesCheckedAt and removeAllianceRenewalEvents) to invoke
requestUpdate() once a removal occurs (or once after the loop if multiple
removals) to force an update.

In `@src/core/execution/TradeShipExecution.ts`:
- Line 192: The change to TradeShipExecution using this.srcPort.tile() when
calling srcPort.owner().addGold alters the addGold event signature and requires
a core test that verifies the source-port gold bonus emits with the tile
context; add a unit test in the core test suite that constructs the minimal game
state (a srcPort with owner and tile, and a TradeShipExecution invocation or
equivalent helper), triggers the gold-award path (calling
TradeShipExecution.execute or the relevant method), and asserts that addGold was
called/emitted with both the correct gold amount and the source port's tile;
reference TradeShipExecution, srcPort.owner().addGold, and srcPort.tile() when
locating where to add the test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7eb593e0-e168-4c22-a070-e9932bb9bd9b

📥 Commits

Reviewing files that changed from the base of the PR and between 219f694 and baf6832.

📒 Files selected for processing (16)
  • index.html
  • resources/lang/en.json
  • src/client/Utils.ts
  • src/client/hud/GameRenderer.ts
  • src/client/hud/layers/ActionableEvents.ts
  • src/client/hud/layers/ControlPanel.ts
  • src/client/hud/layers/EventsDisplay.ts
  • src/core/execution/NukeExecution.ts
  • src/core/execution/TradeShipExecution.ts
  • src/core/game/Game.ts
  • src/core/game/GameImpl.ts
  • src/core/game/GameUpdates.ts
  • src/core/game/PlayerImpl.ts
  • src/core/game/UnitImpl.ts
  • tests/client/graphics/layers/ActionableEventsAlliance.test.ts
  • tests/core/executions/NukeExecution.test.ts
✅ Files skipped from review due to trivial changes (1)
  • resources/lang/en.json

new HoverHighlightController(game, eventBus, transformHandler, view),
new AttackingTroopsOverlay(game, transformHandler, eventBus, userSettings),
eventsDisplay,
actionableEvents,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Verify actionableEvents is valid before adding to layers.

Line 279 adds actionableEvents to the layers array without confirming the element was found. If the querySelector at Line 124 fails, this will add an invalid element to the renderer.

This issue is linked to the guard problem at Line 124-132. Fixing that guard will resolve both issues.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/hud/GameRenderer.ts` at line 279, In GameRenderer, ensure the
element returned by the querySelector for "actionableEvents" is validated before
being appended to the layers array: update the guard around the querySelector
(the code that locates actionableEvents) to check for null/undefined and only
push actionableEvents into layers if it is a truthy HTMLElement; if the selector
fails, skip adding it (or log/debug) so layers never contains an invalid entry.
Ensure references to actionableEvents and the layers array are updated
accordingly so downstream code always receives a valid element.

@evanpelle evanpelle changed the title Improve Notifications Improve Notification Panell May 21, 2026
@evanpelle evanpelle changed the title Improve Notification Panell Improve Notification Panel May 21, 2026
@evanpelle evanpelle marked this pull request as ready for review May 21, 2026 13:15
@evanpelle evanpelle requested a review from a team as a code owner May 21, 2026 13:15
@evanpelle evanpelle added this to the v32 milestone May 21, 2026
@evanpelle evanpelle merged commit 41ef675 into main May 21, 2026
14 checks passed
@evanpelle evanpelle deleted the notifs branch May 21, 2026 18:50
@github-project-automation github-project-automation Bot moved this from Development to Complete in OpenFront Release Management May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Complete

Development

Successfully merging this pull request may close these issues.

Improve notification panel

2 participants